package com.auth.cloud.auth.service;

import com.auth.cloud.auth.dto.LoginRequest;
import com.auth.cloud.auth.dto.LoginResponse;
import com.auth.cloud.auth.dto.RegisterRequest;
import com.auth.cloud.common.entity.User;
import com.auth.cloud.common.exception.BusinessException;
import com.auth.cloud.common.result.ResultCode;
import com.auth.cloud.common.util.JwtUtil;
import com.auth.cloud.common.util.PasswordUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 认证服务
 *
 * @author auth-cloud
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {

    private final UserService userService;
    private final JwtUtil jwtUtil;
    private final RedisTemplate<String, Object> redisTemplate;

    private static final String CAPTCHA_PREFIX = "captcha:";
    private static final String REFRESH_TOKEN_PREFIX = "refresh_token:";
    private static final String BLACKLIST_PREFIX = "blacklist:";

    /**
     * 用户登录
     */
    public LoginResponse login(LoginRequest request) {
        // 验证验证码
        validateCaptcha(request.getCaptchaKey(), request.getCaptcha());

        // 查询用户
        User user = userService.getByUsername(request.getUsername());
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 验证密码
        if (!PasswordUtil.matches(request.getPassword(), user.getPassword())) {
            throw new BusinessException(ResultCode.PASSWORD_ERROR);
        }

        // 检查用户状态
        if (user.getStatus() == 0) {
            throw new BusinessException(ResultCode.USER_DISABLED);
        }

        // 生成Token
        String accessToken = jwtUtil.generateToken(user.getUsername(), user.getId());
        String refreshToken = generateRefreshToken(user.getId());

        // 存储刷新Token
        redisTemplate.opsForValue().set(
                REFRESH_TOKEN_PREFIX + user.getId(),
                refreshToken,
                7,
                TimeUnit.DAYS
        );

        // 更新登录信息
        userService.updateLoginInfo(user.getId());

        // 构建响应
        LoginResponse response = new LoginResponse();
        response.setAccessToken(accessToken);
        response.setRefreshToken(refreshToken);
        response.setExpiresIn(86400L); // 24小时
        response.setUserId(user.getId());
        response.setUsername(user.getUsername());
        response.setNickname(user.getNickname());
        response.setAvatar(user.getAvatar());

        return response;
    }

    /**
     * 用户注册
     */
    public void register(RegisterRequest request) {
        // 验证密码
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "两次输入的密码不一致");
        }

        // 验证验证码
        validateCaptcha(request.getCaptchaKey(), request.getCaptcha());

        // 检查用户名是否存在
        if (userService.existsByUsername(request.getUsername())) {
            throw new BusinessException(ResultCode.USER_ALREADY_EXIST);
        }

        // 检查邮箱是否存在
        if (StringUtils.hasText(request.getEmail()) && userService.existsByEmail(request.getEmail())) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "邮箱已被注册");
        }

        // 检查手机号是否存在
        if (StringUtils.hasText(request.getPhone()) && userService.existsByPhone(request.getPhone())) {
            throw new BusinessException(ResultCode.PARAM_ERROR.getCode(), "手机号已被注册");
        }

        // 创建用户
        User user = new User();
        user.setUsername(request.getUsername());
        user.setPassword(PasswordUtil.encode(request.getPassword()));
        user.setNickname(request.getNickname());
        user.setEmail(request.getEmail());
        user.setPhone(request.getPhone());
        user.setStatus(1); // 启用状态

        userService.save(user);
    }

    /**
     * 刷新Token
     */
    public LoginResponse refreshToken(String token) {
        if (!token.startsWith("Bearer ")) {
            throw new BusinessException(ResultCode.TOKEN_INVALID);
        }

        String refreshToken = token.substring(7);
        Long userId = jwtUtil.getUserIdFromToken(refreshToken);

        // 验证刷新Token
        String storedRefreshToken = (String) redisTemplate.opsForValue().get(REFRESH_TOKEN_PREFIX + userId);
        if (!refreshToken.equals(storedRefreshToken)) {
            throw new BusinessException(ResultCode.TOKEN_INVALID);
        }

        // 查询用户
        User user = userService.getById(userId);
        if (user == null || user.getStatus() == 0) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        // 生成新的访问Token
        String newAccessToken = jwtUtil.generateToken(user.getUsername(), user.getId());

        // 构建响应
        LoginResponse response = new LoginResponse();
        response.setAccessToken(newAccessToken);
        response.setRefreshToken(refreshToken);
        response.setExpiresIn(86400L);
        response.setUserId(user.getId());
        response.setUsername(user.getUsername());
        response.setNickname(user.getNickname());
        response.setAvatar(user.getAvatar());

        return response;
    }

    /**
     * 用户登出
     */
    public void logout(String token) {
        if (!token.startsWith("Bearer ")) {
            return;
        }

        String accessToken = token.substring(7);
        Long userId = jwtUtil.getUserIdFromToken(accessToken);

        // 将Token加入黑名单
        redisTemplate.opsForValue().set(
                BLACKLIST_PREFIX + accessToken,
                userId,
                86400L,
                TimeUnit.SECONDS
        );

        // 删除刷新Token
        redisTemplate.delete(REFRESH_TOKEN_PREFIX + userId);
    }

    /**
     * 生成验证码
     */
    public String generateCaptcha() {
        String captchaKey = UUID.randomUUID().toString();
        String captcha = generateRandomCaptcha();
        
        // 存储验证码
        redisTemplate.opsForValue().set(
                CAPTCHA_PREFIX + captchaKey,
                captcha,
                5,
                TimeUnit.MINUTES
        );

        return captchaKey + ":" + captcha;
    }

    /**
     * 验证验证码
     */
    private void validateCaptcha(String captchaKey, String captcha) {
        String storedCaptcha = (String) redisTemplate.opsForValue().get(CAPTCHA_PREFIX + captchaKey);
        if (storedCaptcha == null) {
            throw new BusinessException(ResultCode.CAPTCHA_EXPIRED);
        }
        if (!storedCaptcha.equalsIgnoreCase(captcha)) {
            throw new BusinessException(ResultCode.CAPTCHA_ERROR);
        }
        // 验证成功后删除验证码
        redisTemplate.delete(CAPTCHA_PREFIX + captchaKey);
    }

    /**
     * 生成刷新Token
     */
    private String generateRefreshToken(Long userId) {
        return jwtUtil.generateToken("refresh", userId);
    }

    /**
     * 生成随机验证码
     */
    private String generateRandomCaptcha() {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder captcha = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            captcha.append(chars.charAt((int) (Math.random() * chars.length())));
        }
        return captcha.toString();
    }
}
